package com.youlai.boot.factory.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.youlai.boot.common.constant.SystemConstants;
import com.youlai.boot.common.model.KeyValue;
import com.youlai.boot.common.model.Option;
import com.youlai.boot.system.enums.MenuTypeEnum;
import com.youlai.boot.system.model.entity.Menu;
import com.youlai.boot.system.model.form.MenuForm;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youlai.boot.factory.mapper.ClothingCategoryMapper;
import com.youlai.boot.factory.service.ClothingCategoryService;
import com.youlai.boot.factory.model.entity.ClothingCategory;
import com.youlai.boot.factory.model.form.ClothingCategoryForm;
import com.youlai.boot.factory.model.query.ClothingCategoryQuery;
import com.youlai.boot.factory.model.vo.ClothingCategoryVO;
import com.youlai.boot.factory.converter.ClothingCategoryConverter;

import java.util.*;
import java.util.stream.Collectors;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;

/**
 * 服装分类服务实现类
 *
 * @author youlaitech
 * @since 2025-08-16 00:26
 */
@Service
@RequiredArgsConstructor
public class ClothingCategoryServiceImpl extends ServiceImpl<ClothingCategoryMapper, ClothingCategory> implements ClothingCategoryService {

    private final ClothingCategoryConverter clothingCategoryConverter;

    /**
    * 获取分页列表
    *
    * @param queryParams 查询参数
    * @return {@link IPage<ClothingCategoryVO>} 服装分类分页列表
    */
    @Override
    public IPage<ClothingCategoryVO> getClothingCategoryPage(ClothingCategoryQuery queryParams) {
        Page<ClothingCategoryVO> pageVO = this.baseMapper.getClothingCategoryPage(
                new Page<>(queryParams.getPageNum(), queryParams.getPageSize()),
                queryParams
        );
        return pageVO;
    }

    /**
     * 加载选项列表
     *
     * @param onlyParent {@link ClothingCategoryQuery}
     */
    @Override
    public List<Option<Long>> listOptions(boolean onlyParent) {
        List<ClothingCategory> categoryList = this.list(new LambdaQueryWrapper<ClothingCategory>()
                .orderByAsc(ClothingCategory::getSort)
        );
        return buildCategoryOptions(SystemConstants.ROOT_NODE_ID, categoryList);
    }

    /**
     * 获取详情
     *
     * @param id 服装分类ID
     * @return 服装分类表单数据
     */
    @Override
    public ClothingCategoryForm getClothingCategoryFormData(Long id) {
        ClothingCategory entity = this.getById(id);
        return clothingCategoryConverter.toForm(entity);
    }

    /**
     * 新增
     *
     * @param formData 服装分类表单对象
     * @return 是否新增成功
     */
    @Override
    public boolean saveClothingCategory(ClothingCategoryForm formData) {
        if (Objects.equals(formData.getParentId(), formData.getId())) {
            throw new RuntimeException("父级菜单不能为当前菜单");
        }
        ClothingCategory entity = clothingCategoryConverter.toEntity(formData);
        String treePath = generateTreePath(formData.getParentId());
        entity.setTreePath(treePath);
        // 修改菜单如果有子菜单，则更新子菜单的树路径
        updateChildrenTreePath(entity.getId(), treePath);
        return this.save(entity);
    }



    /**
     * 更新子的树路径
     *
     * @param id       当前菜单ID
     * @param treePath 当前菜单树路径
     */
    private void updateChildrenTreePath(Long id, String treePath) {
        List<ClothingCategory> children = this.list(new LambdaQueryWrapper<ClothingCategory>().eq(ClothingCategory::getParentId, id));
        if (CollectionUtil.isNotEmpty(children)) {
            // 子菜单的树路径等于父菜单的树路径加上父菜单ID
            String childTreePath = treePath + "," + id;
            this.update(new LambdaUpdateWrapper<ClothingCategory>()
                    .eq(ClothingCategory::getParentId, id)
                    .set(ClothingCategory::getTreePath, childTreePath)
            );
            for (ClothingCategory child : children) {
                // 递归更新子菜单
                updateChildrenTreePath(child.getId(), childTreePath);
            }
        }
    }


    /**
     * treePath路径生成
     *
     * @param parentId 父ID
     * @return 父节点路径以英文逗号(, )分割，eg: 1,2,3
     */
    private String generateTreePath(Long parentId) {
        if (SystemConstants.ROOT_NODE_ID.equals(parentId)) {
            return String.valueOf(parentId);
        } else {
            ClothingCategory parent = this.getById(parentId);
            return parent != null ? parent.getTreePath() + "," + parent.getId() : null;
        }
    }

    /**
     * 更新
     *
     * @param id   服装分类ID
     * @param formData 服装分类表单对象
     * @return 是否修改成功
     */
    @Override
    public boolean updateClothingCategory(Long id,ClothingCategoryForm formData) {
        ClothingCategory entity = clothingCategoryConverter.toEntity(formData);
        return this.updateById(entity);
    }

    /**
     * 删除
     *
     * @param ids 服装分类ID，多个以英文逗号(,)分割
     * @return 是否删除成功
     */
    @Override
    public boolean deleteClothingCategorys(String ids) {
        Assert.isTrue(StrUtil.isNotBlank(ids), "删除的服装分类数据为空");
        // 逻辑删除
        List<Long> idList = Arrays.stream(ids.split(","))
                .map(Long::parseLong)
                .toList();
        return this.removeByIds(idList);
    }


    /**
     * 树形列表
     *
     * @param queryParams {@link ClothingCategoryQuery}
     */
    @Override
    public List<ClothingCategoryVO> listTreeCategories(ClothingCategoryQuery queryParams) {
        List<ClothingCategory> categories = this.list(new LambdaQueryWrapper<ClothingCategory>()
                .like(StrUtil.isNotBlank(queryParams.getName()), ClothingCategory::getName, queryParams.getName())
                .orderByAsc(ClothingCategory::getSort)
        );
        // 获取所有分类ID
        Set<Long> categoryIds = categories.stream()
                .map(ClothingCategory::getId)
                .collect(Collectors.toSet());

        // 获取所有父级ID
        Set<Long> parentIds = categories.stream()
                .map(ClothingCategory::getParentId)
                .collect(Collectors.toSet());

        // 获取根节点ID（递归的起点），即父节点ID中不包含在部门ID中的节点，注意这里不能拿顶级菜单 O 作为根节点，因为菜单筛选的时候 O 会被过滤掉
        List<Long> rootIds = parentIds.stream()
                .filter(id -> !categoryIds.contains(id))
                .toList();

        // 使用递归函数来构建菜单树
        return rootIds.stream()
                .flatMap(rootId -> buildCategoryTree(rootId, categories).stream())
                .collect(Collectors.toList());
    }



    /**
     * 递归生成列表
     *
     * @param parentId 父级ID
     * @param clothingCategoryList 菜单列表
     * @return 菜单列表
     */
    private List<ClothingCategoryVO> buildCategoryTree(Long parentId, List<ClothingCategory> clothingCategoryList) {
        return CollectionUtil.emptyIfNull(clothingCategoryList)
                .stream()
                .filter(category -> category.getParentId().equals(parentId))
                .map(entity -> {
                    ClothingCategoryVO clothingCategoryVO = clothingCategoryConverter.toVo(entity);
                    List<ClothingCategoryVO> children = buildCategoryTree(entity.getId(), clothingCategoryList);
                    clothingCategoryVO.setChildren(children);
                    return clothingCategoryVO;
                }).toList();
    }




    /**
     * 递归生成菜单下拉层级列表
     *
     * @param parentId 父级ID
     * @param categoryList 菜单列表
     * @return 菜单下拉列表
     */
    private List<Option<Long>> buildCategoryOptions(Long parentId, List<ClothingCategory> categoryList) {
        List<Option<Long>> categoryOptions = new ArrayList<>();

        for (ClothingCategory category : categoryList) {
            if (category.getParentId().equals(parentId)) {
                Option<Long> option = new Option<>(category.getId(), category.getName());
                List<Option<Long>> subCategoryOptions = buildCategoryOptions(category.getId(), categoryList);
                if (!subCategoryOptions.isEmpty()) {
                    option.setChildren(subCategoryOptions);
                }
                categoryOptions.add(option);
            }
        }

        return categoryOptions;
    }

}
